﻿// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they bagin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
// 
// - Sun Tsu,
// "The Art of War"

namespace Infrastructure.Logging
{
    /// <summary>
    /// The log4net Thread Context.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The <c>ThreadContext</c> provides a location for thread specific debugging 
    /// information to be stored.
    /// The <c>ThreadContext</c> properties override any <see cref="GlobalContext"/>
    /// properties with the same name.
    /// </para>
    /// <para>
    /// The thread context has a properties map and a stack.
    /// The properties and stack can 
    /// be included in the output of log messages. The <see cref="log4net.Layout.PatternLayout"/>
    /// supports selecting and outputting these properties.
    /// </para>
    /// <para>
    /// The Thread Context provides a diagnostic context for the current thread. 
    /// This is an instrument for distinguishing interleaved log
    /// output from different sources. Log output is typically interleaved
    /// when a server handles multiple clients near-simultaneously.
    /// </para>
    /// <para>
    /// The Thread Context is managed on a per thread basis.
    /// </para>
    /// </remarks>
    /// <example>Example of using the thread context properties to store a username.
    /// <code lang="C#">
    /// ThreadContext.Properties["user"] = userName;
    ///	log.Info("This log message has a ThreadContext Property called 'user'");
    /// </code>
    /// </example>
    /// <example>Example of how to push a message into the context stack
    /// <code lang="C#">
    ///	using(ThreadContext.Stacks["NDC"].Push("my context message"))
    ///	{
    ///		log.Info("This log message has a ThreadContext Stack message that includes 'my context message'");
    ///	
    ///	} // at the end of the using block the message is automatically popped 
    /// </code>
    /// </example>
    /// <threadsafety static="true" instance="true" />
    /// <author>Nicko Cadell</author>
    public static class ThreadContext
    {
        #region Data members

        /// <summary>
        /// wrapper for the real context properties.
        /// </summary>
        private static readonly ThreadContextProperties sProp;

        /// <summary>
        /// wrapper for the real context stacks.
        /// </summary>
        private static readonly ThreadContextStacks sStacks;

        #endregion

        
        /// <summary>
        /// Init the wrappers for the context collections.
        /// </summary>
        static ThreadContext()
        {
            sProp = new ThreadContextProperties( log4net.ThreadContext.Properties );
            sStacks = new ThreadContextStacks( log4net.ThreadContext.Stacks );
        }

        /// <summary>
        /// The thread properties map
        /// </summary>
        /// <value>
        /// The thread properties map
        /// </value>
        /// <remarks>
        /// <para>
        /// The <c>ThreadContext</c> properties override any <see cref="GlobalContext"/>
        /// properties with the same name.
        /// </para>
        /// </remarks>
        public static ThreadContextProperties Properties
        {
            get { return sProp; }
        }

        /// <summary>
        /// The thread stacks
        /// </summary>
        /// <value>
        /// stack map
        /// </value>
        /// <remarks>
        /// <para>
        /// The thread local stacks.
        /// </para>
        /// </remarks>
        public static ThreadContextStacks Stacks
        {
            get { return sStacks; }
        }

        /// <summary>
        /// Get\Set the user name value.
        /// </summary>
        public static string Username
        {
            get { return (string)sProp["UserName"]; }
            set { sProp["UserName"] = value; }
        }

        /// <summary>
        /// Get\Set the session id value.
        /// </summary>
        public static string SessionId
        {
            get { return (string)sProp["SessionID"]; }
            set { sProp["SessionID"] = value; }
        }
    }
}